package org.haifi.game.reflection;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.haifi.game.action.GameBaseAction;
import org.haifi.game.annotation.MethodId;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

import com.google.common.collect.Lists;

/**
 * 缓存反射的各种数据
 * 
 * 这里@lazy无效，因为这时取到的applicationContext可能还未初始化完
 * 
 * @author joycube2
 * 
 */
@Component
@Lazy(false)
public class GameReflect implements ApplicationContextAware {
	private ApplicationContext applicationContext;

	/**
	 * 所有的指令id
	 */
	private static List<Short> allCmdIds = Lists.newArrayList();
	/**
	 * 指令id与action的对应
	 */
	private static Map<Short, GameBaseAction> actions = new HashMap<Short, GameBaseAction>();
	/**
	 * 指令id与method的对应
	 */
	private static Map<Short, Method> methods = new HashMap<Short, Method>();

	/**
	 * 返回数据与指令id对应关系
	 * 
	 * 用于把返回数据进行编码
	 */
	private static Map<Class, Short> returnCmdIds = new HashMap<Class, Short>();
	/**
	 * 返回参数与指令id对应关系
	 */
	private static Map<Short, Class> paramCmdIds = new HashMap<Short, Class>();

	@Override
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		this.applicationContext = applicationContext;
	}

	/**
	 * 初始化反射的各种数据
	 */
	@PostConstruct
	public void init() {
		log.info("初始化反射数据.");
		Map<String, GameBaseAction> allActions = applicationContext
				.getBeansOfType(GameBaseAction.class);
		for (String key : allActions.keySet()) {
			log.info("processing " + key);
			GameBaseAction action = allActions.get(key);

			for (Method method : action.getClass().getMethods()) {
				MethodId methodId = method.getAnnotation(MethodId.class);
				if (methodId != null) {
					short cmdId = methodId.value();
					if (methods.containsKey(cmdId)) {
						log.error("cmdId exists,ignor:" + cmdId);
						continue;
					}
					actions.put(cmdId, action);
					methods.put(cmdId, method);
					log.info("add method:" + cmdId + "\t" + method.getName());
					// 取出参数及返回值
					Class clazz = method.getReturnType();
					if (clazz != void.class) {
						returnCmdIds.put(clazz, cmdId);
					}
					clazz = method.getParameterTypes()[0];
					paramCmdIds.put(cmdId, clazz);
					allCmdIds.add(cmdId);
				}
			}
		}
	}

	public static short getReturnCmdId(Class clazz) {
		return returnCmdIds.get(clazz);
	}

//	public static short getParamCmdId(Class clazz) {
//		return paramCmdIds.get(clazz);
//	}

	public static Map<Short, Class> getParamCmdIds() {
		return paramCmdIds;
	}

	public static Map<Class, Short> getReturnCmdIds() {
		return returnCmdIds;
	}

	public static GameBaseAction getGameBaseAction(short cmdId) {
		return actions.get(cmdId);
	}

	public static Method getMethod(short cmdId) {
		return methods.get(cmdId);
	}

	public static List<Short> getAllCmdIds() {
		return allCmdIds;
	}

	private static final Log log = LogFactory.getLog(GameReflect.class);
}
